/**
 * @Author: 陈瑞鹏
 * @Date:   2022-10-17 11:53:56
 * @Last Modified by:   陈瑞鹏
 * @Last Modified time: 2022-11-17 10:29:55
 */

import abiao_utils from 'abiao_utils';
import redis from 'redis';
import configDefault from '../config/config.default';
import User from '../models/user/user.model';

const expired_subKey = `__keyevent@${configDefault.redisConfig.db}__:expired`;

export default class Redis {

    static saveRedis = redis.createClient(configDefault.redisConfig);  // 存取端
    static subRedis = redis.createClient(configDefault.redisConfig);   // 订阅端
    static pubRedis = redis.createClient(configDefault.redisConfig);   // 发布端

    static sub_name = {
        exit: 'exit', // 退出
        message: 'message', // 普通消息
        chatMessage: 'chatMessage', // 聊天消息
        offlineTime: 'offlinetime', // 离线时间
        payCall: 'payCall', // 充值回调
        equipBuild: 'equipBuild',// 装备打造
    }

    constructor() {

    }

    /**
     * 写入字符串
     * @param key
     * @param val
     * @param ttl 过期时间
     */
    static set(key: string, val: string, ttl?: number | undefined): void {
        this.saveRedis.set(key, val);
        if (ttl) {
            this.saveRedis.expire(key, ttl);
        }
    }

    /**
     * 获取字符串
     * @param key
     * @returns
     */
    static get(key: string): Promise<unknown> {
        return new Promise((resolve: (value: unknown) => void, reject: (reason?: any) => void) => {
            this.saveRedis.get(key, (err: Error | null, data: string | null) => {
                if (err) reject(err);
                resolve(data);
            })
        })
    }


    static ttl(key: string) {
        return new Promise((resolve: (value: unknown) => void, reject: (reason?: any) => void) => {
            this.saveRedis.ttl(key, (err, ttl) => {
                if (err) reject(err);
                resolve(ttl);
            });


        })
    }

    /**
     * 获取所有匹配的key
     * @param key
     * @returns
     */
    static get_all_keys(key: string): Promise<unknown> {
        return new Promise((resolve: (value: unknown) => void, reject: (reason?: any) => void) => {
            this.saveRedis.keys(key + '*', (err: Error | null, data: string[]) => {
                if (err) reject(err);
                resolve(data)
            })
        })
    }

    /**
     * 
     * @param key 
     */
    static get_all_data(key: string) {
        return new Promise((resolve: (value: unknown) => void, reject: (reason?: any) => void) => {
            this.saveRedis.hgetall(key, (data) => {
                resolve(data);
            })
        })

    }

    /**
     * 自增数
     * @param key
     * @returns
     */
    static incr(key: string): Promise<unknown> {
        return new Promise((resolve: (value: unknown) => void, reject: (reason?: any) => void) => {
            this.saveRedis.incr(key, (err: Error | null, data: number) => {
                if (err) reject(err);
                resolve(data)
            })
        })
    }


    /**
     * 自减数
     * @param key
     * @returns
     */
    static decr(key: string): Promise<unknown> {
        return new Promise((resolve: (value: unknown) => void, reject: (reason?: any) => void) => {
            this.saveRedis.decr(key, (err: Error | null, data: number) => {
                if (err) reject(err);
                resolve(data)
            })
        })
    }


    /**
     * 删除key
     * @param key
     */
    static del(key: string): void {
        this.saveRedis.del(key);
    }


    /**
     * 写入hash
     * @param key
     * @param skey
     * @param val
     */
    static async hset(key: string, skey: string, val: string) {
        this.saveRedis.hset(key, skey, val);
    }

    /**
     * 添加有序集合
     * @param key 
     * @param score 
     * @param val 
     */
    static async hZadd(key: string, score: number, val: number) {
        this.saveRedis.zadd(key, score, val);
    }


    /**
     * 读取hash
     * @param key
     * @param skey
     */
    static hget(key: string, skey: string) {
        return new Promise((resolve: (value: unknown) => void, reject: (reason?: any) => void) => {
            this.saveRedis.hget(key, skey, (err, data: any) => {
                if (err) reject(err);
                resolve(data);
            })
        })
    }

    /**
     * 删除hash
     * @param key
     * @param skey
     */
    static hdel(key: string, skey: string) {
        this.saveRedis.hdel(key, skey)
    }


    /**
     * 客户端订阅消息
     */
    static client_sub() {
        this.subRedis.on('ready', () => {
            this.subRedis.subscribe(expired_subKey);
            this.subRedis.subscribe(this.sub_name.exit);
            this.subRedis.subscribe(this.sub_name.message);
            this.subRedis.subscribe(this.sub_name.chatMessage);
            this.subRedis.subscribe(this.sub_name.offlineTime);
            this.subRedis.subscribe(this.sub_name.payCall);
            this.subRedis.subscribe(this.sub_name.equipBuild);
        })

        this.subRedis.on('error', (err) => {
            console.log(`redis Error ${err}`);
        })

        this.subRedis.on('subscribe', (channel, count) => {
            console.log(`${channel} 订阅成功`);
        })

        this.subRedis.on('message', async (channel, message) => {
            await this.pub_message_handle(channel, message);
        })

        this.subRedis.on("unsubscribe", (channel, count) => {
            console.log("client unsubscribed from" + channel + ", " + count + " total subscriptions")
        });
    }

    /**
     * 客户端发布消息
     * @param channel 发布频道
     * @param data 发布内容
     * @param sid
     */
    static client_pub(channel: string, data: any, sid?: string) {
        this.pubRedis.publish(channel, JSON.stringify({ data, sid }), (err, result) => {
            if (err) {
                console.log(`publish Error ${err}`);
            }
        })
    }


    /**
     * 发布消息处理
     * @param channel 频道
     * @param message 内容
     */
    static async pub_message_handle(channel: string, message: any) {
        let data = typeof message == 'string' ? message : JSON.parse(message);
        // 判断来源是否等于过期key
        // if (channel == expired_subKey) {
        //     console.log('过期event', channel, message, expired_subKey);
        //     if (message.indexOf('online') != -1) {
        //         let info = message.split(':');
        //         await User.updateOne({ roleId: info[1] }, { isOnline: false, sid: '' });
        //         await OnlineTime.updateOne({ roleId: info[1] }, { offlineTime: new Date().getTime() });
        //         await timeing.updateOfflineTime(info[1]);
        //     }
        // } else {
        //     data = JSON.parse(data)
        //     if (data.data.room) {
        //         room.send_server_room_msg(channel, data.data, data.data.room);
        //     } else {
        //         socket.send_private_msg(channel, data.data, data.sid);
        //     }
        // }
    }

    // 设置用户在线状态
    static async set_user_online_status(roleId: number) {
        let key = `${configDefault.qhApiQuery.gid}_online:${roleId}`;
        await Redis.set(key, abiao_utils.date(), 30);
        let sid = await Redis.get(`${configDefault.qhApiQuery.gid}_sid:${roleId}`);
        await User.updateOne({ roleId }, { isOnline: true, sid });
    }

    /**
     * 检查用户在线状态
     */
    static async check_user_online_status() {
        let UserRes: any = await User.find({ status: true, isOnline: true, updateTime: { $gte: abiao_utils.date(7, 7) } });
        for (const iterator of UserRes) {
            let redisCheckRoleId = await Redis.get(`${configDefault.qhApiQuery.gid}_online:${iterator.roleId}`);
            if (redisCheckRoleId) {
                await User.updateOne({ roleId: iterator.roleId }, { isOnline: true, updateTime: abiao_utils.date() });
            } else {
                let offlineTime = new Date().getTime();
                await User.updateOne({ roleId: iterator.roleId }, { isOnline: false, sid: '', updateTime: abiao_utils.date() });
                // await OnlineTime.updateOne({ roleId: iterator.roleId }, { offlineTime });
                // await timeing.updateOfflineTime(iterator.roleId);
            }
        }
    }
}
